/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package webproxy;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author MinhVu
 */

class Request_Thread extends Thread
{
// <editor-fold defaultstate="collapsed" desc="1. Thuoc Tinh ">
    private int buffer =  1024;
    private int ithreadCount;
    private ArrayList<ACL_BlackList> listDomain;
    private ArrayList<ACL_BlackList> listIP;
    private Config config;
    private Socket sockProxyClient;
    private Socket sockProxyServer;
    private HTTPRequest httpRequest;
    private HTTPResponse httpResponse;
    //-------- Cac bien dung de gui van nhan goi tin
    private byte[] dataFromClient;
    private byte[] dataFromServer;
    private String strRequestFromClient;
    private String strResponseFromServer;
    private InputStream isInFromClient;
    private BufferedInputStream bffIsInFromServer;
    private PrintStream psOutToClient;
    private PrintStream psOutToServer;
    int iTotalSize;
    //--------- ACL----
    private int index_domain =-1;
    private int index_ip = -1;
    //---  Cache
    private MyCache cache;
    private FileOutputStream fos;
    private FileInputStream fis;
    private PrintStream psOutToFile;
    
 // </editor-fold>
    
// <editor-fold defaultstate="collapsed" desc="2. Get-Set ">
    public ArrayList<ACL_BlackList> getListDomain()
    {
        return listDomain;
    }
    public ArrayList<ACL_BlackList> getListIP()
    {
        return listIP;
    }
    public Config getConfig()
    {
        return config;
    }
    public void setIthreadCount(int i)
    {
        ithreadCount = i;
    }
    public int getIthreadCount()
    {
        return ithreadCount;
    }
    public void setListDomain(ArrayList<ACL_BlackList> ls)
    {
        listDomain = ls;
    }
    public void setListIP(ArrayList<ACL_BlackList> ls)
    {
        listIP = ls;
    }
    public void setConfig(Config cof)
    {
        config = cof;
    }
// </editor-fold>
    
// <editor-fold defaultstate="collapsed" desc="3. Phuong Thuc ">    
    public Request_Thread(Socket s,String threadName,Config cof,
            ArrayList<ACL_BlackList> lsDomain,ArrayList<ACL_BlackList> lsIP) throws IOException
    {
        httpRequest = new HTTPRequest();
        httpResponse = new HTTPResponse();
        config =cof;
        listDomain = lsDomain;
        listIP = lsIP;
        this.setName(threadName);
        ithreadCount++;
        System.out.println("Khởi tạo " + this.getName());
        //-------- client socket
        sockProxyClient = s;

        isInFromClient = sockProxyClient.getInputStream();
        psOutToClient = new PrintStream(sockProxyClient.getOutputStream());
        //-------- cache
        cache = new MyCache();
        
        //Ham init dung de load cac tap tin trong cache luu vao hashtable de kiem tra
        //Nhung ta khong can load truoc 
        //ta co the kiem tra truc tiep trong thuc muc vao bien File
        //cache.Init();
    }
        @Override
    public void run()
    {
        try {
            dataFromClient = new byte[1024];
            //Nhan goi tin tu Client gui len proxy
            isInFromClient.read(dataFromClient);
            strRequestFromClient = new String(dataFromClient);
            httpRequest.PhanTichGoiTin(strRequestFromClient);
            
            //Cap nhat duong dan den thu muc cache
            String strPath = cache.getBasePath()+File.separatorChar +httpRequest.getHost();
            //Kiem tra xem co thu muc Cache chua, neu chua co thi tao thu muc cache
            cache.CreateDir();
            cache.setBasePath(strPath);

            if(KiemTra_Domain())
            {
                send404();
                return;
            }
            //Chi xu ly cac reques la GET-POST va domain khong bi cam
            if(!(httpRequest.getMethod().equals("GET")||httpRequest.getMethod().equals("POST")))
            {
                send404();
                return ;
            }
            
            //Neu la phuong thuc GET moi xu ly cache
            //Kiemtra config xem co cache du lieu khong
            //Kiem tra goi tin yeu cau co trong cache hay khong
            if(httpRequest.getMethod().equals("GET") &&
                config.IsCache() && cache.IsCached(httpRequest.getUrl()))
            {
                //Lay du lieu tu cache o day
                System.out.println("Load Cache --------");
                fis = new FileInputStream(cache.getBasePath() + File.separatorChar
                            + cache.CreateFileName(httpRequest.getUrl()));
                byte dataFromCache[]=new byte[1024];
                fis.read(dataFromCache);
                strResponseFromServer = new String(dataFromCache);
                httpResponse.PhanTichGoiTin(strResponseFromServer);
                //Lay length cua goi tin nhan duoc tu server

                if(KiemTra_ACL())
                    return;
                
                psOutToClient.write(dataFromCache);
                
                dataFromCache = new byte[1024*1024*50];
                fis.read(dataFromCache);
                psOutToClient.write(dataFromCache);
                sockProxyClient.close();
                System.out.println( "----------------- " +httpResponse.getContent_Type());
                System.out.println("Kết thúc " + this.getName());
                return;
            }

            
            
            //Tao socket ket noi tu proxy den server
            if(!config.IsChangeProxy())
                sockProxyServer = new Socket(httpRequest.getHost(),80);
            else
            {
                //Proxy ket noi den 1 proxy khac
                sockProxyServer = new Socket(config.getChangeProxy_Host(),
                                                config.getChangeProxy_Port());
            }

            //Lay ip cua server
            httpResponse.setIP(sockProxyServer.getInetAddress().getHostAddress());

            if(KiemTra_IP())
            {
                send404();
                return;
            }

            bffIsInFromServer = new BufferedInputStream(sockProxyServer.getInputStream());
            psOutToServer = new PrintStream(sockProxyServer.getOutputStream()); 

            //Gui request len cho server
            psOutToServer.write(dataFromClient);
            psOutToServer.flush();         


            //Nhan goi tin response tu server ve proxy
            //
            int size;
            int count =0;
            dataFromServer = new byte[buffer];
            size = bffIsInFromServer.read(dataFromServer,0,buffer);
            iTotalSize = size;
            strResponseFromServer = new String(dataFromServer);
            httpResponse.PhanTichGoiTin(strResponseFromServer);
            //Lay length cua goi tin nhan duoc tu server

            if(KiemTra_ACL())
                return;

            System.out.println(this.getName()+" - (" + count +")  -  "+(httpResponse.getLength())
                    +" - "+iTotalSize+ "  size :   " +size +" - "+ httpResponse.getContent_Type());

            //gui goi tin dau tien chua header ve cho Client
            psOutToClient.write(dataFromServer,0,size);
            psOutToClient.flush();
            //
            // Luu cache
            //

            boolean flag_cache = true;
            if(httpRequest.getUrl().indexOf("?") !=-1)
                flag_cache = false;
            if(flag_cache && httpRequest.getMethod().equals("GET") && config.IsCache() && config.getFreeSize()> 0)
                    //&& (httpResponse.getStatus() == 200 ||httpResponse.getStatus() ==304 ))
            {
                cache.CreateDir();
                fos = new FileOutputStream(cache.getBasePath()+ File.separatorChar
                        +cache.CreateFileName(httpRequest.getUrl()));
                psOutToFile = new PrintStream(fos);
                psOutToFile.write(dataFromServer);
                psOutToFile.flush();
                config.setFreeSize(config.getFreeSize()- size);
                config.OutputFile("Default.config");
            }
            if(size < 1024 && iTotalSize > httpResponse.getLength())
            {
                sockProxyServer.close();
                sockProxyClient.close();
                return;
            }
            //Đây là hàm while chính, xử lý việc truyền nhận dử liệu từ server->prox->client
            while((size = bffIsInFromServer.read(dataFromServer,0,buffer)) >-1)
            {
                iTotalSize += size;
                count ++;
                System.out.println(this.getName()+" - (" + count +")  -  "+(httpResponse.getLength()) 
                        +" - "+iTotalSize+ "  size :   " +size +" - "+ httpResponse.getContent_Type());
                
//                psOutToServer.write(1);
//                psOutToServer.flush();
                
                //Gui goi tin tu proxy ve cho client    
                psOutToClient.write(dataFromServer,0,size);
                psOutToClient.flush();
                //
                // tiep tuc luu file cache
                //
                   if(flag_cache && httpRequest.getMethod().equals("GET") && config.IsCache() && config.getFreeSize()> 0)
                    {
                        psOutToFile.write(dataFromServer);
                        psOutToFile.flush();
                        config.setFreeSize(config.getFreeSize()- size);
                        config.OutputFile("Default.config");
                    }
//                for(int j=0;j<size;j++)
//                {
//                    System.out.println(this.getName()+ "  -  " +j+" - " +dataFromServer[j] );
//                }
                byte one = dataFromServer[size-4];
                byte two = dataFromServer[size-3];
                byte tree = dataFromServer[size-2];
                byte four = dataFromServer[size-1];
                System.out.println(this.getName()+ "  -  " + one +  "  -  " +two + "  -  " + tree +"  -  " +four );
                if(four ==0 || (size < 1024 && iTotalSize > httpResponse.getLength())
                  || (iTotalSize + 1000 > httpResponse.getLength() && tree == 10 && four ==10)
                  || (one == 13 && two == 10 && tree == 13 && four == 10))
                   break;
            }//end while     

            sockProxyServer.close();
            sockProxyClient.close();
            System.out.println("Kết thúc " + this.getName());
            
        } catch (IOException ex) {
            Logger.getLogger(Request_Thread.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
     public void send404() throws IOException
    {
        psOutToClient.println("HTTP/1.0 200 OK");
        psOutToClient.println("Content-Type: text/html");
        psOutToClient.println("Server: NTV Proxy 1.0");
        psOutToClient.println("");
        fis = new FileInputStream(System.getProperty("user.dir") +File.separatorChar +"404.html");
        byte temp[]=new byte[1024];
        fis.read(temp);
        psOutToClient.write(temp);

        psOutToClient.flush();
        psOutToClient.close();
        
        sockProxyClient.close();
    }
    public boolean KiemTra_ACL()
    {           
        boolean flag_filter = false; //Khong loc j het
        if(httpResponse.getContent_Type() == null)
            return false;
      // String a = httpResponse.getContent_Type();
        if(httpResponse.getContent_Type().indexOf("image") !=-1)
        {
            if(config.getFilter().getImage())
                flag_filter = true; // chan tat ca

            if(index_domain !=-1)
            {
                if(listDomain.get(index_domain).getFilter().getImage())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            if(index_ip !=-1)
            {
                if(listIP.get(index_ip).getFilter().getImage())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            return flag_filter;
        }
        if(httpResponse.getContent_Type().indexOf("application") !=-1)
        {
            if(config.getFilter().getFlash())
                flag_filter = true;
            if(index_domain !=-1)
            {
                if(listDomain.get(index_domain).getFilter().getFlash())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
             if(index_ip !=-1)
            {
                if(listIP.get(index_ip).getFilter().getFlash())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            return flag_filter;
        }
        if(httpResponse.getContent_Type().indexOf("video") !=-1)
        {
            if(config.getFilter().getVideo())
                flag_filter = true;
            if(index_domain !=-1)
            {
                if(listDomain.get(index_domain).getFilter().getVideo())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            if(index_ip !=-1)
            {
                if(listIP.get(index_ip).getFilter().getVideo())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            return flag_filter;
        }
        if(httpResponse.getContent_Type().indexOf("audio") !=-1)
        {
            if(config.getFilter().getAudio())
                flag_filter = true;
            if(index_domain !=-1)
            {
                if(listDomain.get(index_domain).getFilter().getAudio())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            if(index_ip!=-1)
            {
                if(listIP.get(index_ip).getFilter().getAudio())
                    flag_filter = true;
                else
                    flag_filter = false;
            }
            return flag_filter;
        }
        return flag_filter;
    }
    public boolean KiemTra_Domain()
    {
        boolean flag_domain = false;//Khong chan
        //Kiem tra  Filter  trong file config
            if(config.getFilter().getLock())
                flag_domain = true; //Chan tat ca cac trang web
        
        //Kiem tra xem domain ma Client yeu co nam trong danh sach cam hay khong      
        //Neu domain co trong danh sach nhung khong bi lock thi van duoc duyet
        //      mac du' trong file config clock =true
        for(int i = 0;i<listDomain.size();i++)
        {
            String stra = listDomain.get(i).getName();
            String strb = httpRequest.getHost();
            int d = stra.indexOf(strb);
            int e = strb.indexOf(stra);
            
            //if(listDomain.get(i).getName().indexOf(httpRequest.getHost()) !=-1 ||
               if( httpRequest.getHost().indexOf(listDomain.get(i).getName()) !=-1)
            {
                index_domain = i;
                if(listDomain.get(i).getFilter().getLock())
                    flag_domain = true; //Chan trang web nay
                else
                    flag_domain = false; // khong chan trang web nay
            }
        }
        return flag_domain;
    }
    public boolean KiemTra_IP()
    {
        boolean flag_ip = false; //Khong chan
        //Kiem tra ip nay co bi cam hay khong
        for(int i = 0;i<listIP.size();i++)
            if(listIP.get(i).getName().equals(httpResponse.getIP()))
            {
                index_ip = i;
                if(listIP.get(i).getFilter().getLock())
                    flag_ip = true; // chan ip nay
            }
        return flag_ip;
    }
   
// </editor-fold>
        
}  